using System;
using System.Linq;
using EasyDapr.Infrastructure.Response;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;

namespace EasyDapr.Infrastructure.Attribute
{
    /// <summary>
    /// Api action统一处理过滤器
    /// 处理正常返回值 {code:200,body:{}}
    /// </summary>
    public class ApiResponseFilterAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            //模型验证
            if (!context.ModelState.IsValid)
            {
                throw new ApplicationException(context.ModelState.Values.First(p => p.Errors.Count > 0).Errors[0]
                    .ErrorMessage);
            }

            base.OnActionExecuting(context);
        }

        /// <summary>
        /// 处理正常返回的结果对象，进行统一json格式包装
        /// 异常只能交由ExceptionFilterAttribute 去处理 
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            //特殊处理：对有ApiIgnoreAttribute标签的，不进行返回结果包装，原样输出
            if (context.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
            {
                var isDefined =
                    controllerActionDescriptor.EndpointMetadata.Any(a => a.GetType() == typeof(ApiIgnoreFilterAttribute));
                if (isDefined)
                {
                    return;
                }
            }

            // 返回结果为JsonResult的请求进行Result包装
            if (context.Exception == null)
            {
                context.Result = context.Result switch
                {
                    JsonResult jsonResult => new JsonResult(new ApiResult<object>
                    {
                        Message = "succeed", Success = true, StatusCode = 200, Data = jsonResult.Value
                    }),
                    ObjectResult result => new JsonResult(new ApiResult<object>
                    {
                        Message = "succeed", Success = true, StatusCode = 200, Data = result.Value
                    }),
                    _ => context.Result
                };

                base.OnActionExecuted(context);
            }
            else
            {
                throw context.Exception;
            }
        }
    }
}